{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 1.NiN简介"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "LeNet、AlexNet和VGG都有一个共同的设计模式：通过一系列的卷积层与汇聚（池化）层来提取空间结构特征；然后通过全连接层对特征的表征进行处理。 AlexNet和VGG对LeNet的改进主要在于如何扩大和加深这两个模块。 或者，可以想象在这个过程的早期使用全连接层。然而，如果使用了全连接层，可能会完全放弃表征的空间结构。 网络中的网络（NiN）提供了一个非常简单的解决方案：在每个像素的通道上分别使用多层感知机 (各个通道同一位置上的像素加权求和)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "全连接层的两个缺陷：\n",
    "\n",
    "1. 参数量过大\n",
    "2. 缺乏空间结构信息"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "针对这两个缺陷，NiN完全放弃了全连接层，使用多个1×1卷积，针对每个通道上的对应位置像素进行多次全连接\n",
    "\n",
    "有三个好处：\n",
    "\n",
    "1. 在单个像素进行多通道全连接，可以将多个通道特征加权求和，得到一个新的特征，这个过程为多通道特征融合\n",
    "2. 仅在单像素内计算，不会破坏特征图的空间信息\n",
    "3. 1×1卷积参数量大大减少"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 2.NiN块的结构"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<img src=\"https://zyc-learning-1309954661.cos.ap-nanjing.myqcloud.com/machine-learning-pic/image-20240810192241449.png\" alt=\"image-20240810192241449\" style=\"zoom:67%;\" />"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Sequential(\n",
       "  (0): Conv2d(1, 128, kernel_size=(3, 3), stride=(4, 4))\n",
       "  (1): ReLU()\n",
       "  (2): Conv2d(128, 128, kernel_size=(1, 1), stride=(1, 1))\n",
       "  (3): ReLU()\n",
       "  (4): Conv2d(128, 128, kernel_size=(1, 1), stride=(1, 1))\n",
       "  (5): ReLU()\n",
       ")"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import torch\n",
    "from torch import nn\n",
    "\n",
    "def block(in_channels, out_channels, kernel_size, stride=1, padding=0):\n",
    "    return nn.Sequential(\n",
    "        nn.Conv2d(in_channels, out_channels, kernel_size, stride, padding),\n",
    "        nn.ReLU(),\n",
    "        nn.Conv2d(out_channels, out_channels, 1),\n",
    "        nn.ReLU(),\n",
    "        nn.Conv2d(out_channels, out_channels, 1),\n",
    "        nn.ReLU()\n",
    "    )\n",
    "\n",
    "block(1, 128, 3, 4)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 3.搭建网络"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "----------------------------------------------------------------\n",
      "        Layer (type)               Output Shape         Param #\n",
      "================================================================\n",
      "            Conv2d-1           [-1, 96, 54, 54]          11,712\n",
      "              ReLU-2           [-1, 96, 54, 54]               0\n",
      "            Conv2d-3           [-1, 96, 54, 54]           9,312\n",
      "              ReLU-4           [-1, 96, 54, 54]               0\n",
      "            Conv2d-5           [-1, 96, 54, 54]           9,312\n",
      "              ReLU-6           [-1, 96, 54, 54]               0\n",
      "         MaxPool2d-7           [-1, 96, 26, 26]               0\n",
      "            Conv2d-8          [-1, 256, 26, 26]         614,656\n",
      "              ReLU-9          [-1, 256, 26, 26]               0\n",
      "           Conv2d-10          [-1, 256, 26, 26]          65,792\n",
      "             ReLU-11          [-1, 256, 26, 26]               0\n",
      "           Conv2d-12          [-1, 256, 26, 26]          65,792\n",
      "             ReLU-13          [-1, 256, 26, 26]               0\n",
      "        MaxPool2d-14          [-1, 256, 12, 12]               0\n",
      "           Conv2d-15          [-1, 384, 12, 12]         885,120\n",
      "             ReLU-16          [-1, 384, 12, 12]               0\n",
      "           Conv2d-17          [-1, 384, 12, 12]         147,840\n",
      "             ReLU-18          [-1, 384, 12, 12]               0\n",
      "           Conv2d-19          [-1, 384, 12, 12]         147,840\n",
      "             ReLU-20          [-1, 384, 12, 12]               0\n",
      "        MaxPool2d-21            [-1, 384, 5, 5]               0\n",
      "           Conv2d-22             [-1, 10, 5, 5]          34,570\n",
      "             ReLU-23             [-1, 10, 5, 5]               0\n",
      "           Conv2d-24             [-1, 10, 5, 5]             110\n",
      "             ReLU-25             [-1, 10, 5, 5]               0\n",
      "           Conv2d-26             [-1, 10, 5, 5]             110\n",
      "             ReLU-27             [-1, 10, 5, 5]               0\n",
      "AdaptiveAvgPool2d-28             [-1, 10, 1, 1]               0\n",
      "          Flatten-29                   [-1, 10]               0\n",
      "================================================================\n",
      "Total params: 1,992,166\n",
      "Trainable params: 1,992,166\n",
      "Non-trainable params: 0\n",
      "----------------------------------------------------------------\n",
      "Input size (MB): 0.19\n",
      "Forward/backward pass size (MB): 24.13\n",
      "Params size (MB): 7.60\n",
      "Estimated Total Size (MB): 31.92\n",
      "----------------------------------------------------------------\n"
     ]
    }
   ],
   "source": [
    "import torchsummary\n",
    "\n",
    "class NiNNet(nn.Module):\n",
    "    def __init__(self, ):\n",
    "        super(NiNNet, self).__init__()\n",
    "        self.structure = nn.Sequential(\n",
    "            block(1, 96, 11, stride=4),\n",
    "            nn.MaxPool2d(kernel_size=3, stride=2),\n",
    "            block(96, 256, 5, padding=2),\n",
    "            nn.MaxPool2d(3, 2),\n",
    "            block(256, 384, 3, padding=1),\n",
    "            nn.MaxPool2d(3, 2),\n",
    "            block(384, 10, 3, padding=1),\n",
    "            nn.AdaptiveAvgPool2d(output_size=(1,1)),\n",
    "            nn.Flatten()\n",
    "        )\n",
    "    \n",
    "    def forward(self, x):\n",
    "        return self.structure(x)\n",
    "\n",
    "device = 'cuda' if torch.cuda.is_available() else 'cpu'\n",
    "net = NiNNet().to(device)\n",
    "torchsummary.summary(net, input_size=(1,224,224))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 4.开始训练"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "epoch:1, loss:2.293711079717445, accuracy:0.1\n",
      "epoch:2, loss:2.098574751984082, accuracy:0.3538\n",
      "epoch:3, loss:1.6238565910091278, accuracy:0.3647\n",
      "epoch:4, loss:1.5627047708039599, accuracy:0.3864\n",
      "epoch:5, loss:1.455349967932142, accuracy:0.4262\n",
      "epoch:6, loss:1.2480214419903786, accuracy:0.5887\n",
      "epoch:7, loss:1.1233065130868192, accuracy:0.5557\n",
      "epoch:8, loss:1.0409140265318377, accuracy:0.6999\n",
      "epoch:9, loss:0.9713336126382417, accuracy:0.7183\n",
      "epoch:10, loss:0.9230082952645796, accuracy:0.7169\n",
      "epoch:11, loss:0.9156322355971915, accuracy:0.6727\n",
      "epoch:12, loss:0.8714862214222646, accuracy:0.7277\n",
      "epoch:13, loss:0.8429224231858243, accuracy:0.7078\n",
      "epoch:14, loss:0.8287588453242011, accuracy:0.7085\n",
      "epoch:15, loss:0.80606365934618, accuracy:0.7143\n",
      "epoch:16, loss:0.7897934560328405, accuracy:0.7403\n",
      "epoch:17, loss:0.7749897099252957, accuracy:0.7229\n",
      "epoch:18, loss:0.7622302579981431, accuracy:0.7374\n",
      "epoch:19, loss:0.751405657608626, accuracy:0.7756\n",
      "epoch:20, loss:0.7396032085169607, accuracy:0.774\n"
     ]
    },
    {
     "data": {
      "image/png": "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c+bMqfOyzKZNm66Yd/vtt3P77bc35aNalL+/PwsWLKjRPsWdedL+al/dlyftr/bVfXna/jbE4U7PRERERJqTBsoTERERSymMiIiIiKUURkRERMRSCiMiIiJiKbcPIy+++CJdunQhICCA4cOHs23btnqXf/fdd+nduzcBAQEkJiaydu3aVqr06ixcuJChQ4cSEhJCVFQUKSkpHDx4sN51Xn/9dWw2W40pICCglSpuul//+tdX1N27d+9613HV49qlS5cr9tVmszF79uxal3e1Y/r5559z0003ERMTg81mY9WqVTXeNwyDZ555hujoaAIDA0lOTubQoUMNbtfR731rqG9fy8vLefLJJ0lMTCQ4OJiYmBhmzJjByZMn691mU74LraGh4zpz5swr6p4wYUKD23XG4woN729t32Gbzcbzzz9f5zad9di2FLcOI2+//Tbz5s1jwYIF7Ny5k6SkJMaPH8/p06drXX7Lli1MmzaN+++/n127dpGSkkJKSgp79uxp5cod99lnnzF79my++uorNm7cSHl5OTfccAOFhYX1rhcaGsqpU6fsU2ZmZitVfHX69u1bo+4vv/yyzmVd+bh+8803NfZz48aNAPXeKu9Kx7SwsJCkpCRefPHFWt///e9/z1/+8hcWL17M119/TXBwMOPHj6ekpKTObTr6vW8t9e1rUVERO3fu5Omnn2bnzp28//77HDx4kJtvvrnB7TryXWgtDR1XgAkTJtSoe/ny5fVu01mPKzS8v5fu56lTp3j11Vex2Wzcdttt9W7XGY9tizHc2LBhw4zZs2fbX1dWVhoxMTHGwoULa13+jjvuMCZPnlxj3vDhw40HH3ywRetsCadPnzYA47PPPqtzmddee80ICwtrvaKayYIFC4ykpKRGL+9Ox/WRRx4xunXrZlRVVdX6vqseU8MwDMBYuXKl/XVVVZXRsWNH4/nnn7fPy83NNfz9/Y3ly5fXuR1Hv/dWuHxfa7Nt2zYDMDIzM+tcxtHvghVq29d7773XmDJlikPbcYXjahiNO7ZTpkwxxo4dW+8yrnBsm5PbnhkpKytjx44dJCcn2+d5eXmRnJzM1q1ba11n69atNZYHGD9+fJ3LO7O8vDwAIiIi6l3uwoULxMfHExcXx5QpU9i7d29rlHfVDh06RExMDF27duXuu+/m6NGjdS7rLse1rKyMJUuW8LOf/azeASNd9ZheLj09naysrBrHLiwsjOHDh9d57JryvXdWeXl52Gw2wsPD613Oke+CM9m0aRNRUVH06tWLhx9+mHPnztW5rDsd1+zsbNasWcP999/f4LKuemybwm3DyNmzZ6msrLR3U1+tQ4cOZGVl1bpOVlaWQ8s7q6qqKubOncu1115bb7f7vXr14tVXX+WDDz5gyZIlVFVVMWrUKI4fP96K1Tpu+PDhvP7666xfv56XXnqJ9PR0fvzjH1NQUFDr8u5yXFetWkVubi4zZ86scxlXPaa1qT4+jhy7pnzvnVFJSQlPPvkk06ZNq3cQNUe/C85iwoQJvPHGG6SmpvK73/2Ozz77jIkTJ1JZWVnr8u5yXAH+9a9/ERISwq233lrvcq56bJuqSd3Bi3ObPXs2e/bsafD64siRI2uMnjxq1Cj69OnDP/7xD5599tmWLrPJJk6caH/ev39/hg8fTnx8PO+8806j/rXhqv75z38yceLEeofidtVjKheVl5dzxx13YBgGL730Ur3Luup34c4777Q/T0xMpH///nTr1o1NmzYxbtw4Cytrea+++ip33313gw3LXfXYNpXbnhlp37493t7eZGdn15ifnZ1Nx44da12nY8eODi3vjObMmcPq1av59NNP6dSpk0Pr+vr6MnDgQA4fPtxC1bWM8PBwevbsWWfd7nBcMzMz+fjjj5k1a5ZD67nqMQXsx8eRY9eU770zqQ4imZmZbNy40eGh5Rv6Ljirrl270r59+zrrdvXjWu2LL77g4MGDDn+PwXWPbWO5bRjx8/Nj8ODBpKam2udVVVWRmppa41+Olxo5cmSN5QE2btxY5/LOxDAM5syZw8qVK/nkk09ISEhweBuVlZWkpaURHR3dAhW2nAsXLnDkyJE663bl41rttddeIyoqismTJzu0nqseU4CEhAQ6duxY49jl5+fz9ddf13nsmvK9dxbVQeTQoUN8/PHHtGvXzuFtNPRdcFbHjx/n3Llzddbtysf1Uv/85z8ZPHgwSUlJDq/rqse20axuQduS3nrrLcPf3994/fXXjX379hk///nPjfDwcCMrK8swDMOYPn268ctf/tK+/ObNmw0fHx/jD3/4g7F//35jwYIFhq+vr5GWlmbVLjTaww8/bISFhRmbNm0yTp06ZZ+Kiorsy1y+v7/5zW+MDRs2GEeOHDF27Nhh3HnnnUZAQICxd+9eK3ah0R577DFj06ZNRnp6urF582YjOTnZaN++vXH69GnDMNzruBqGeddA586djSeffPKK91z9mBYUFBi7du0ydu3aZQDGCy+8YOzatct+B8lzzz1nhIeHGx988IHx3XffGVOmTDESEhKM4uJi+zbGjh1r/PWvf7W/buh7b5X69rWsrMy4+eabjU6dOhm7d++u8R0uLS21b+PyfW3ou2CV+va1oKDAePzxx42tW7ca6enpxscff2wMGjTI6NGjh1FSUmLfhqscV8No+L9jwzCMvLw8IygoyHjppZdq3YarHNuW4tZhxDAM469//avRuXNnw8/Pzxg2bJjx1Vdf2d8bPXq0ce+999ZY/p133jF69uxp+Pn5GX379jXWrFnTyhU3DVDr9Nprr9mXuXx/586da//bdOjQwZg0aZKxc+fO1i/eQVOnTjWio6MNPz8/IzY21pg6dapx+PBh+/vudFwNwzA2bNhgAMbBgweveM/Vj+mnn35a63+31ftUVVVlPP3000aHDh0Mf39/Y9y4cVf8HeLj440FCxbUmFff994q9e1renp6nd/hTz/91L6Ny/e1oe+CVerb16KiIuOGG24wIiMjDV9fXyM+Pt544IEHrggVrnJcDaPh/44NwzD+8Y9/GIGBgUZubm6t23CVY9tSbIZhGC166kVERESkHm7bZkRERERcg8KIiIiIWEphRERERCylMCIiIiKWUhgRERERSymMiIiIiKUURkRERMRSCiMiIiJiKYURERERsZTCiIiIiFhKYUREREQspTAiIiIilvr/n+y1bE75YQgAAAAASUVORK5CYII=",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import torch.utils\n",
    "from torchvision import transforms\n",
    "import Module.Utils as myutils\n",
    "\n",
    "epochs = 20\n",
    "lr = 0.1\n",
    "batch_size = 128\n",
    "\n",
    "trans = transforms.Compose(\n",
    "    [\n",
    "        transforms.ToTensor(),\n",
    "        transforms.Resize((224, 224))\n",
    "    ]\n",
    ")\n",
    "_, train_iter, test_iter = myutils.load_data_FMNIST('../data', batch_size, trans)\n",
    "\n",
    "optimizer = torch.optim.SGD(net.parameters(), lr)\n",
    "loss = nn.CrossEntropyLoss()\n",
    "\n",
    "myutils.train(net, train_iter, test_iter, epochs, optimizer, loss, True)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "torch",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.14"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
